﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Text.RegularExpressions;

namespace GW2_Marketeer
{
    class Marketeer
    {
        private int m_nItemCount;
        private List<string> m_listItemNames;
        private Dictionary<string, GWItem> m_dictItems;
        private Dictionary<string, int> m_dictNumItemsToCraft;
        private Dictionary<string, int> m_dictNumItemsToBuy;
        private Dictionary<string, int> m_dictPriceTotalsByItem;
        private int m_nTotalCost;
        private int m_nTotalRevenue;
        private int m_nTotalProfit;
        private double m_dTotalExpectedROI;

        public Marketeer()
        {

        }

        public int GetItemCount()
        {
            return m_nItemCount;
        }

        public List<string> GetListItemNames()
        {
            return m_listItemNames;
        }

        public GWItem GetItemByName(string sName)
        {
            return m_dictItems[sName];
        }

        public Dictionary<string, int> GetShoppingListNumItemsToBuy()
        {
            return m_dictNumItemsToBuy;
        }

        public Dictionary<string, int> GetShoppingListPriceTotals()
        {
            return m_dictPriceTotalsByItem;
        }

        public int GetTotalCost()
        {
            return m_nTotalCost;
        }

        public int GetTotalRevenue()
        {
            return m_nTotalRevenue;
        }

        public int GetTotalProfit()
        {
            return m_nTotalProfit;
        }

        public double GetTotalExpectedROI()
        {
            return m_dTotalExpectedROI;
        }

        private void ResetAllData()
        {
            m_nItemCount = 0;
            m_listItemNames = new List<string>();
            m_dictItems = new Dictionary<string, GWItem>();
            m_dictNumItemsToCraft = new Dictionary<string, int>();
            m_dictNumItemsToBuy = new Dictionary<string, int>();
            m_dictPriceTotalsByItem = new Dictionary<string, int>();
            m_nTotalCost = 0;
            m_nTotalRevenue = 0;
            m_nTotalProfit = 0;
            m_dTotalExpectedROI = 0.0;
        }

        private void ResetAHAndCalculatedData()
        {
            foreach(KeyValuePair<string, GWItem> kvp in m_dictItems)
            {
                GWItem item = kvp.Value;
                item.AuctionHousePrice = 0;
                item.MinimumCalculatedPrice = 0;
                item.CheapestPriceComputed = false;
                item.Profit = 0;
                item.ReturnOnInvestment = 0.0;
            }
            ResetShoppingListData();
        }

        private void ResetShoppingListData()
        {
            m_dictNumItemsToCraft = new Dictionary<string, int>();
            m_dictNumItemsToBuy = new Dictionary<string, int>();
            m_dictPriceTotalsByItem = new Dictionary<string, int>();
            m_nTotalCost = 0;
            m_nTotalRevenue = 0;
            m_nTotalProfit = 0;
            m_dTotalExpectedROI = 0.0;
        }

        private IEnumerable<string> GetComponentsFromRawComponentString(string rawComponentString)
        {
            var componentStrings = rawComponentString.Split(',');
            foreach (var componentString in componentStrings)
            {
                var matches = Regex.Match(componentString, @"([a-zA-Z 1-9]+)\(([1-9]+)\){0,1}");
                if (matches.Groups.Count > 1)
                {
                    var num = int.Parse(matches.Groups[2].Value.ToString());
                    foreach (var i in Enumerable.Range(0, num))
                    {
                        yield return matches.Groups[1].Value;
                    }
                }
                else
                {
                    yield return matches.Groups[1].Value;
                }
            }
        }

        public bool ImportXMLData(string sFileName)
        {
            ResetAllData();
            try
            {
                XDocument doc = XDocument.Load(sFileName);

                var gwItems = from element in doc.Descendants("item")
                              let itemName = element.Element("name").Value.ToString()
                              let itemId = element.Element("ID").Value.ToString()
                              let components = GetComponentsFromRawComponentString(element.Element("components").Value.ToString())
                              select new GWItem(itemName, itemId, components);

                foreach (var gwItem in gwItems)
                {
                    m_dictItems[gwItem.Name] = gwItem;
                }

                m_nItemCount = m_dictItems.Count;
                m_listItemNames.AddRange(m_dictItems.Keys);
            }
            catch 
            {
                return false;
            }

            return true;
        }

        public bool ReadAHPricesFromGUI(Dictionary<string, int> dict)
        {
            ResetAHAndCalculatedData();
            foreach(KeyValuePair<string, int> kvp in dict)
            {
                string sName = kvp.Key;
                GWItem item = m_dictItems[sName];
                item.AuctionHousePrice = kvp.Value;
            }

            return false;
        }

        public void CalculateMinimumPrices()
        {
            for (int i = 0; i < m_nItemCount; i++)
            {
                string sName = m_listItemNames[i];
                GWItem item = m_dictItems[sName];
                ComputeCheapestPriceHelper(item);
            }
        }

        public void ComputeCheapestPriceHelper(GWItem item)
        {
            if (item.CheapestPriceComputed == true)
            {
                return;
            }
            if (item.GetNumComponents() == 0)
            {
                item.MinimumCalculatedPrice = item.AuctionHousePrice;
                item.AddToShoppingList(item.Name);
                item.CheapestPriceComputed = true;
                return;
            }
            else
            {
                int nTotalPrice = 0;
                for(int i = 0; i < item.GetNumComponents(); i++)
                {
                    string sComponentName = item.GetComponentAtIndex(i);
                    GWItem itemComp = m_dictItems[sComponentName];
                    ComputeCheapestPriceHelper(itemComp);
                    nTotalPrice += itemComp.MinimumCalculatedPrice;
                    int numShoppingListcomps = itemComp.GetNumShoppingList();
                    for(int j = 0; j < itemComp.GetNumShoppingList(); j++)
                    {
                        item.AddToShoppingList(itemComp.GetShoppingListItemAtIndex(j));
                    }
                }
                if(nTotalPrice > item.AuctionHousePrice)
                {
                    nTotalPrice = item.AuctionHousePrice;
                    item.ClearShoppingList();
                    item.AddToShoppingList(item.Name);
                }
                item.MinimumCalculatedPrice = nTotalPrice;
                item.CheapestPriceComputed = true;
                return;
            }
        }

        public void CalculateProfit()
        {
            for (int i = 0; i < m_nItemCount; i++)
            {
                string sName = m_listItemNames[i];
                GWItem item = m_dictItems[sName];
                int nAHPrice = item.AuctionHousePrice;
                int nMinPrice = item.MinimumCalculatedPrice;
                double dAHPrice = (double)nAHPrice;
                dAHPrice *= 0.85;
                nAHPrice = (int)dAHPrice;
                int nProfit = nAHPrice - nMinPrice;
                item.Profit = nProfit;
                item.ReturnOnInvestment = (((double)nAHPrice / (double)nMinPrice) - 1.0);
            }
        }

        public void ReadNumToCraftFromGUI(Dictionary<string, int> dict)
        {
            ResetShoppingListData();

            for (int i = 0; i < m_nItemCount; i++)
            {
                string sName = m_listItemNames[i];
                m_dictNumItemsToCraft[sName] = 0;
            }
            foreach (KeyValuePair<string, int> kvp in dict)
            {
                string sName = kvp.Key;
                m_dictNumItemsToCraft[sName] = kvp.Value;
            }
        }

        public void CalculateShoppingList()
        {
            for (int i = 0; i < m_nItemCount; i++)
            {
                string sName = m_listItemNames[i];
                m_dictNumItemsToBuy[sName] = 0;
            }
            for(int i = 0; i < m_nItemCount; i++)
            {
                string sName = m_listItemNames[i];
                int nValue = m_dictNumItemsToCraft[sName];
                GWItem item = m_dictItems[sName];
                for(int j = 0; j < item.GetNumShoppingList(); j++)
                {
                    string sComponent = item.GetShoppingListItemAtIndex(j);
                    m_dictNumItemsToBuy[sComponent] += nValue;
                }
            }
        }

        public void CalculateTotals()
        {
            for (int i = 0; i < m_nItemCount; i++)
            {
                string sName = m_listItemNames[i];
                int nCount = m_dictNumItemsToBuy[sName];
                int nAHPrice = m_dictItems[sName].AuctionHousePrice;
                m_dictPriceTotalsByItem[sName] = nCount * nAHPrice;
            }

            m_nTotalCost = 0;
            m_nTotalRevenue = 0;
            for (int i = 0; i < m_nItemCount; i++)
            {
                string sName = m_listItemNames[i];
                m_nTotalCost += m_dictPriceTotalsByItem[sName];
                m_nTotalRevenue += m_dictNumItemsToCraft[sName] * m_dictItems[sName].AuctionHousePrice;
                
            }

            double dTotalRevenue = (double)m_nTotalRevenue;
            dTotalRevenue *= 0.85;
            m_nTotalRevenue = (int)dTotalRevenue;
            m_nTotalProfit = m_nTotalRevenue - m_nTotalCost;
            double dTotalCost = (double)m_nTotalCost;
            m_dTotalExpectedROI = (dTotalRevenue / dTotalCost) - 1.0;
        }
    }
}
